home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 2000 July / macformat-092.iso / Dreamweaver 3 / Configuration / Shared / MM / Scripts / insertFireworksHTML.js < prev    next >
Encoding:
Text File  |  1999-12-01  |  19.5 KB  |  620 lines

  1. // Copyright 1999 Macromedia, Inc. All rights reserved.
  2.  
  3. // This file contains functions for inserting Fireworks HTML
  4. //
  5. // dependencies:
  6. // $Dreamweaver/Configuration/Shared/MM/Scripts/Class/FileClass.js
  7. //
  8. // errors:
  9. /*
  10. var MSG_copyFilesToSite =
  11.       "Some referenced files are outside of the root folder of site '%s'\n" +
  12.       "and may not be accessible when you publish the site.\n\n" +
  13.       "The referenced files are:\n%s\n\n" +
  14.       "Your root folder is:\n%s\n\n" +
  15.       "Continue copying these files into your site?";
  16. var MSG_folderNotUnderSite =
  17.       "The folder you have selected is not under the site root.\n\n" +
  18.       "Your root folder is:\n%s\n\n" +
  19.       "Please select a folder within the site.";
  20. var MSG_overwriteFiles =
  21.       "Some files being copied already exist in the selected folder.\n\n" +
  22.       "The existing files are:\n%s\n\n" +
  23.       "Do you want to replace the existing files?";
  24. var MSG_copyFailed =
  25.       "Some files could not be copied to the selected folder.\n\n" +
  26.       "The files not copied are:\n%s";
  27. */
  28.  
  29.  
  30. //*************** GLOBALS  *****************
  31.  
  32. //List of unsupported Fireworks JavaScript functions
  33. var LIST_fwSpecificFns = new Array("GrpRestore", "GrpSwap", "GrpDown");
  34.  
  35.  
  36.  
  37. //***************** LOCAL FUNCTIONS  ******************
  38.  
  39. //Returns true if the given document is a Fireworks HTML file.
  40. // Find the Fireworks comment
  41. //
  42. function isFireworksHTML(theHTML) {
  43.   var start, stop, target, retVal = false;
  44.   start = theHTML.indexOf("<!-- Fireworks ");
  45.   if (start != -1) {
  46.     stop = theHTML.indexOf("-->", start);
  47.     if (stop != -1) {
  48.       target = theHTML.indexOf("target.", start);
  49.       retVal = (target >= 0) && (target < stop);
  50.   } }
  51.   return retVal;
  52. }
  53.  
  54.  
  55. //Returns true if the given document is a Fireworks HTML file targeted
  56. // at Dreamweaver.  Find the Dreamweaver string within the Fireworks
  57. // comment.
  58. //
  59. function isDWStyle(theHTML) {
  60.   var start, stop, target, retVal = false;
  61.   start = theHTML.indexOf("<!-- Fireworks ");
  62.   if (start != -1) {
  63.     stop = theHTML.indexOf("-->", start);
  64.     if (stop != -1) {
  65.       target = theHTML.indexOf("Dreamweaver", start);
  66.       retVal = (target >= 0) && (target < stop);
  67.   } }
  68.   return retVal;
  69. }
  70.  
  71.  
  72. //Returns true if the given document contains only supported DW
  73. // behavior functions.  (This should only be an issue for FW1 and FW2)
  74. //
  75. function usesDWBehaviors(theHTML) {
  76.   var fw1or2, searchPatt, retVal = true;
  77.   fw1or2 = (theHTML.indexOf("<!-- Fireworks 1") != -1) ||
  78.            (theHTML.indexOf("<!-- Fireworks 2") != -1);
  79.   if (fw1or2) {
  80.     for (var i=0; retVal && i < LIST_fwSpecificFns.length; i++) {
  81.       searchPatt = new RegExp("function\\s+" + LIST_fwSpecificFns[i] + "\\s*\\(");
  82.       if (theHTML.search(searchPatt) != -1) retVal = false;
  83.   } }
  84.   return retVal;
  85. }
  86.  
  87.  
  88. //Return the HTML that should be inserted at the IP
  89. //
  90. function insertFireworksHTML(fwDOM, fwURL, docRootURL, siteRootURL) {
  91.   var fileList, tagList, jsList;
  92.   var siteURL, sitePath, copyList, folderURL, folder;
  93.   var existsList, failedList, overwrite;
  94.   var targetDOM;
  95.  
  96.   fileList = new FileRefList(fwURL);
  97.   tagList = new TagList(fwDOM, fileList);
  98.   jsList = new JsRefList(fwDOM, fileList, tagList);
  99.  
  100.   siteURL = dreamweaver.getSiteRoot();
  101.  
  102.   if (docRootURL && siteURL) {
  103.     sitePath = MMNotes.localURLToFilePath(siteURL);
  104.     siteName = site.getCurrentSite();
  105.     copyList = fileList.getOutsideOfSite(siteURL);
  106.  
  107.     if (copyList.length > 0) {
  108.       while (true) {
  109.         copy = confirm(printf(MSG_copyFilesToSite,
  110.                               siteName, displayArray(copyList, 5, '\n'), sitePath));
  111.  
  112.         // copy files to the site.
  113.         if (copy) {
  114.           while (true) {
  115.             folderURL =  dw.browseForFolderURL(LABEL_selectFolder, siteURL);
  116.             folder = new File(folderURL);
  117.             inSite = (folderURL.indexOf(siteURL) == 0)
  118.             if (!folderURL || (folder.exists() && inSite)) break;
  119.             alert(printf(MSG_folderNotUnderSite, sitePath));
  120.           }
  121.  
  122.           if (!folderURL) continue;
  123.           else if (folder.exists()) {
  124.             existsList = fileList.getTargetExists(folder.getAbsolutePath(), siteURL);
  125.             if (existsList.length > 0)
  126.               overwrite = confirm(printf(MSG_overwriteFiles, displayArray(existsList, 5, '\n')));
  127.             failedList = fileList.copyToFolder(folder.getAbsolutePath(), siteURL, overwrite);
  128.             if (failedList.length >0)
  129.               alert(printf(MSG_copyFailed, displayArray(failedList, 10, '\n')));
  130.         } }
  131.         break;
  132.   } } }
  133.  
  134.   // update the URLs
  135.   fileList.updateURLs(docRootURL, siteRootURL);
  136.  
  137.   // make the tag names unique
  138.   targetDOM = dreamweaver.getDocumentDOM('document');
  139.   tagList.makeNamesUnique(targetDOM);
  140.  
  141.   retVal = getInsertedHTML(fwDOM);
  142.  
  143.   return retVal;
  144. }
  145.  
  146.  
  147. //Returns the HTML that should be inserted into the current document.
  148. //
  149. function getInsertedHTML(sourceDOM) {
  150.   var retVal = sourceDOM.body.innerHTML;
  151.   var start = '', stop = '', item;
  152.   var startExp = /<!-+\s*BEGIN COPYING[\w\s]*-+>\s*/;
  153.   var stopExp  = /\s*<!-+\s*STOP COPYING[\w\s]*-+>/;
  154.   item = retVal.match(startExp);
  155.   if (item != null) start = item.index + item[0].length;
  156.   item = retVal.match(stopExp);
  157.   if (item != null) stop = item.index;
  158.   if (start && stop)
  159.     retVal = retVal.substring(start,stop);
  160.  
  161.   return retVal;
  162. }
  163.  
  164.  
  165. //******************* GENERAL CLASSES **********************
  166.  
  167. //*************************************
  168.  
  169. //File reference node
  170. //
  171. function FileRef(fileURL, docURL) {
  172.   this.file = new File(fileURL, docURL);
  173.   this.refs = new Array();
  174. }
  175.  
  176.  
  177. //List of referenced files
  178. //
  179. function FileRefList(theDocURL) {
  180.   this.docURL = theDocURL;
  181.   this.list = new Array();
  182. }
  183. FileRefList.prototype.add = FileRefList_add;
  184. FileRefList.prototype.getOutsideOfSite = FileRefList_getOutsideOfSite;
  185. FileRefList.prototype.getTargetExists = FileRefList_getTargetExists;
  186. FileRefList.prototype.copyToFolder = FileRefList_copyToFolder;
  187. FileRefList.prototype.updateURLs = FileRefList_updateURLs;
  188.  
  189. function FileRefList_add(fileURL, refObj) {
  190.   var node;
  191.   for (var i=0; !node && i < this.list.length; i++)
  192.     if (this.list[i].file.getPath() == fileURL) node = this.list[i];
  193.   if (!node) {
  194.     node = new FileRef(fileURL, this.docURL);
  195.     this.list.push(node);
  196.   }
  197.   node.refs.push(refObj);
  198. }
  199.  
  200. //Returns the list of files which are outside of the current site root
  201. function FileRefList_getOutsideOfSite(theSiteURL) {
  202.   var file, retList = new Array();
  203.   for (var i=0; i < this.list.length; i++) {
  204.     file = this.list[i].file;
  205.     if (file.exists() && file.getAbsolutePath().indexOf(theSiteURL) != 0)
  206.       retList.push(MMNotes.localURLToFilePath(file.getAbsolutePath()));
  207.   }
  208.   return retList;
  209. }
  210.  
  211. //Returns the list of files which already exist in the target folder
  212. function FileRefList_getTargetExists(theFolderURL, theSiteURL) {
  213.   var file, newFile, retList = new Array();
  214.   for (var i=0; i < this.list.length; i++) {
  215.     file = this.list[i].file;
  216.     if (file.exists() && file.getAbsolutePath().indexOf(theSiteURL) != 0) {
  217.       newFile = new File(theFolderURL + File.separator + file.getName());
  218.       if (newFile.exists())
  219.         retList.push(MMNotes.localURLToFilePath(newFile.getAbsolutePath()));
  220.   } }
  221.   return retList;
  222. }
  223.  
  224. //Returns the list of files that could not be copied
  225. function FileRefList_copyToFolder(theFolderURL, theSiteURL, overwrite) {
  226.   var file, newFile, retList = new Array();
  227.   for (var i=0; i < this.list.length; i++) {
  228.     file = this.list[i].file;
  229.     if (file.exists() && file.getAbsolutePath().indexOf(theSiteURL) != 0) {
  230.       newFile = new File(theFolderURL + File.separator + file.getName());
  231.       if (newFile.exists() && !overwrite) {
  232.         file.setPath(newFile.getPath());
  233.       } else {
  234.         result = file.copyTo(newFile.getPath());
  235.         if (!result)
  236.           retList.push(MMNotes.localURLToFilePath(newFile.getAbsolutePath()));
  237.         file.setPath(newFile.getPath());
  238.   } } }
  239.   return retList;
  240. }
  241.  
  242. function FileRefList_updateURLs(newDocURL, newSiteURL) {
  243.   var newRef, fullURL, index, filePath, docPath;
  244.   for (var i=0; i < this.list.length; i++) with (this) {
  245.     if (list[i].file.exists()) {
  246.       newRef = '';
  247.       fullURL = list[i].file.getAbsolutePath();
  248.       if (newSiteURL && fullURL.indexOf(newSiteURL) == 0)
  249.         newRef = fullURL.substring(newSiteURL.length); // site relative
  250.       else if (newDocURL && fullURL.indexOf(newDocURL) == 0)
  251.         newRef = fullURL.substring(newDocURL.length); // doc relative, below doc
  252.       else if (newDocURL) {  // doc relative, above doc
  253.         for (index=0; index < fullURL.length && index < newDocURL.length; index++)
  254.           if (fullURL.charAt(index) != newDocURL.charAt(index)) break;
  255.         index = fullURL.substring(0, index).lastIndexOf(File.separator)+1; // backup to last directory
  256.         filePath = fullURL.substring(index);
  257.         docPath = newDocURL.substring(index);
  258.         if (docPath && docPath.indexOf('|') == -1) {  // image on a separate drive
  259.           for (var j=0; j < docPath.length; j++)
  260.             if (docPath.charAt(j) == File.separator) newRef += "../";
  261.           newRef += filePath;
  262.       } }
  263.       if (!newRef) newRef = fullURL;  // local file ref
  264.  
  265.       for (var j=0; j < list[i].refs.length; j++)
  266.         list[i].refs[j].setURL(newRef);
  267.   } }
  268. }
  269.  
  270.  
  271. //*************************************
  272.  
  273. //Image Tag
  274. //
  275. function ImageTag(theImgTag) {
  276.   this.imgTag = theImgTag;
  277.   this.name = this.imgTag.name;
  278.   this.jsRefs = new Array();  // list of js references to this tag
  279. }
  280. ImageTag.prototype.getURL = ImageTag_getURL;
  281. ImageTag.prototype.setURL = ImageTag_setURL;
  282. ImageTag.prototype.addJsRef = ImageTag_addJsRef;
  283. ImageTag.prototype.makeNameUnique = ImageTag_makeNameUnique;
  284.  
  285. function ImageTag_getURL() {
  286.   return this.imgTag.src;
  287. }
  288.  
  289. function ImageTag_setURL(newURL) {
  290.   this.imgTag.src = newURL;
  291. }
  292.  
  293. function ImageTag_addJsRef(theJsRef) {
  294.   this.jsRefs.push(theJsRef);
  295. }
  296.  
  297. function ImageTag_makeNameUnique(theNameList) {
  298.   var index=0, count = 2, newName = this.name;
  299.   while (index < theNameList.length)
  300.     if (theNameList[index] == newName) {
  301.       newName = this.name + "_" + count++; // increment name
  302.       index=0; // re-start search
  303.     } else index++;
  304.   if (newName != this.name) {
  305.     this.imgTag.name = newName;
  306.     for (var i=0; i < this.jsRefs.length; i++)
  307.       this.jsRefs[i].setTagName(newName);
  308.   }
  309. }
  310.  
  311.  
  312. //*************************************
  313.  
  314. //List of HTML tags
  315. //
  316. function TagList(sourceDOM, theFileList) {
  317.   this.list = new Array();
  318.   this.init(sourceDOM, theFileList);
  319. }
  320. TagList.prototype.init = TagList_init;
  321. TagList.prototype.addJsRef = TagList_addJsRef;
  322. TagList.prototype.makeNamesUnique = TagList_makeNamesUnique;
  323. TagList.prototype.fixJsRefs = TagList_fixJsRefs;
  324.  
  325. function TagList_init(sourceDOM, theFileList) {
  326.   var tags, node;
  327.   // add image tags
  328.   tags = sourceDOM.getElementsByTagName("IMG");
  329.   for (var i=0; i < tags.size; i++) {
  330.     node = new ImageTag(tags.item(i));
  331.     this.list.push(node);
  332.     theFileList.add(node.getURL(), node);
  333.   }
  334.   // add flash, director, etc
  335. }
  336.  
  337. function TagList_addJsRef(tagName, refObj) {
  338.   var node;
  339.   for (var i=0; !node && i < this.list.length; i++)
  340.     if (this.list[i].name == tagName) node = this.list[i];
  341.   if (node) node.addJsRef(refObj);
  342. }
  343.  
  344. function TagList_makeNamesUnique(targetDOM) {
  345.   var tags, nameList = new Array();
  346.   // create tag name list
  347.   tags = targetDOM.getElementsByTagName("IMG");
  348.   for (var i=0; i < tags.size; i++)
  349.     nameList.push(tags.item(i).name);
  350.   // make names unique
  351.   for (var i=0; i < this.list.length; i++)
  352.     if (this.list[i].makeNameUnique != null)
  353.       this.list[i].makeNameUnique(nameList);
  354. }
  355.  
  356. // update the JS references if they are being inserted in layers
  357. function TagList_fixJsRefs(targetDOM, selection) {
  358. }
  359.  
  360.  
  361. //*************************************
  362.  
  363. //JavaScript File reference
  364. //
  365. function JsFileRef(theTag, theAttr, theFileURL) {
  366.   this.tag = theTag;
  367.   this.attr = theAttr;
  368.   this.url = stripSpaces(theFileURL);
  369. }
  370. JsFileRef.prototype.getURL = JsFileRef_getURL;
  371. JsFileRef.prototype.setURL = JsFileRef_setURL;
  372.  
  373. function JsFileRef_getURL() {
  374.   return stripQuotes(this.url);
  375. }
  376.  
  377. function JsFileRef_setURL(newURL) {
  378.   var jsCalls, index;
  379.   jsCalls = this.tag.getAttribute(this.attr);
  380.   index = jsCalls.indexOf(this.url);
  381.   if (index >= 0) {
  382.     jsCalls = jsCalls.substring(0,index) +
  383.               "'" + newURL + "'" +
  384.               jsCalls.substring(index + this.url.length);
  385.     this.tag.setAttribute(this.attr, jsCalls);
  386.   }
  387. }
  388.  
  389.  
  390. //*************************************
  391.  
  392. //JavaScript Tag reference
  393. //
  394. function JsTagRef(theTag, theAttr, theTagRef, theRefType) {
  395.   this.tag = theTag;
  396.   this.attr = theAttr;
  397.   this.tagRef = stripSpaces(theTagRef);
  398.   this.refType = theRefType; // NS4.0REF or IE4.0REF or objName
  399.  
  400.   // Convert to the new find object behavior parameters
  401.   if (this.refType == "NS4.0REF")
  402.     this.setTagRef("'" + getNameFromRef(stripQuotes(this.tagRef)) + "'");
  403.   else if (this.refType == "IE4.0REF")
  404.     this.setTagName('');
  405. }
  406. JsTagRef.prototype.getTagName = JsTagRef_getTagName;
  407. JsTagRef.prototype.setTagName = JsTagRef_setTagName;
  408. JsTagRef.prototype.setTagRef = JsTagRef_setTagRef;
  409.  
  410. function JsTagRef_getTagName() {
  411.   var retVal, index;
  412.   retVal = stripQuotes(this.tagRef);
  413.   index = retVal.indexOf('?')
  414.   if (index >= 0) retVal = retVal.substring(0, index); // remove frame name
  415.   return retVal;
  416. }
  417.  
  418. function JsTagRef_setTagName(newName) {
  419.   var index, newRef, tagName;
  420.   if (this.tagRef != "''") with (this) {
  421.     tagName = this.getTagName();
  422.     index = tagRef.indexOf(tagName);
  423.     if (index >= 0) {
  424.       newRef = tagRef.substring(0, index) +
  425.                newName +
  426.                tagRef.substring(index + tagName.length);
  427.       setTagRef(newRef);
  428.   } }
  429. }
  430.  
  431. function JsTagRef_setTagRef(newRef) {
  432.   var jsCalls, refStart;
  433.   with (this) {
  434.     jsCalls = tag.getAttribute(attr);
  435.     refStart = jsCalls.indexOf(tagRef);
  436.     if (refStart >= 0) {
  437.       jsCalls = jsCalls.substring(0,refStart) +
  438.                 newRef +
  439.                 jsCalls.substring(refStart + tagRef.length);
  440.       tag.setAttribute(attr, jsCalls);
  441.       this.tagRef = newRef;
  442.   } }
  443. }
  444.  
  445.  
  446. //*************************************
  447.  
  448. //List of JavaScript calls which have file or tag references
  449. //
  450. function JsRefList(sourceDOM, theFileList, theTagList) {
  451.   this.list = new Array();
  452.   this.init(sourceDOM, theFileList, theTagList);
  453. }
  454. JsRefList.prototype.init = JsRefList_init;
  455. JsRefList.prototype.add = JsRefList_add;
  456. JsRefList.prototype.getBehArgs = JsRefList_getBehArgs;
  457.  
  458. JsRefList.TagList = new Array("A", "AREA", "IMG");
  459. JsRefList.AttrList = new Array("onClick", "onMouseOver", "onMouseOut","onLoad");
  460. JsRefList.swapImageFn  = "MM_swapImage";
  461. JsRefList.nbGroupFn    = "MM_nbGroup";
  462.  
  463.  
  464. function JsRefList_init(sourceDOM, theFileList, theTagList) {
  465.   for (var i=0; i < JsRefList.TagList.length; i++) {
  466.     tagList = sourceDOM.getElementsByTagName(JsRefList.TagList[i]);
  467.     for (var j=0; j < tagList.size; j++)
  468.       for (var k=0; k < JsRefList.AttrList.length; k++)
  469.         if (tagList.item(j).getAttribute(JsRefList.AttrList[k]) != null)
  470.           this.add(theFileList, theTagList, tagList.item(j), JsRefList.AttrList[k]);
  471.   }
  472. }
  473.  
  474. function JsRefList_add(theFileList, theTagList, theTag, theAttr) {
  475.   var callString, jsCalls, fnCall, args, argMask, node, mask;
  476.   callString = theTag.getAttribute(theAttr);
  477.   jsCalls = dreamweaver.getTokens(callString, ";");
  478.   for (var i=0; i < jsCalls.length; i++) {
  479.     fnCall = dreamweaver.getTokens(jsCalls[i], "()");
  480.     if (fnCall.length > 1) {
  481.       args = dreamweaver.getTokens(fnCall[1], ",");
  482.       argMask = this.getBehArgs(fnCall[0], jsCalls[i]);
  483.       for (var j=0; j < argMask.length && j < args.length; j++) {
  484.         mask = argMask[j].toUpperCase();
  485.         if (mask == "DEP" || mask == "URL") {
  486.           node = new JsFileRef(theTag, theAttr, args[j]);
  487.           this.list.push(node);
  488.           theFileList.add(node.getURL(), node);
  489.         } else if (mask == "NS4.0REF" || mask == "IE4.0REF") {
  490.           node = new JsTagRef(theTag, theAttr, args[j], mask);
  491.           this.list.push(node);
  492.           theTagList.addJsRef(node.getTagName(), node);
  493.         } else if (mask == "OBJNAME") {
  494.           node = new JsTagRef(theTag, theAttr, args[j], mask);
  495.           this.list.push(node);
  496.           theTagList.addJsRef(node.getTagName(), node);
  497.   } } } }
  498. }
  499.  
  500. function JsRefList_getBehArgs(theFn, theFnCall) {
  501.   var retList= '';
  502.   if (stripSpaces(theFn) == JsRefList.swapImageFn)
  503.     retList = SwapImage_identifyBehaviorArguments(theFnCall);
  504.   if (stripSpaces(theFn) == JsRefList.nbGroupFn)
  505.     retList = NavBarGroup_identifyBehaviorArguments(theFnCall);
  506.   if (retList) retList = retList.split(',');
  507.   return retList;
  508. }
  509.  
  510.  
  511. //******************* BEHAVIOR FUNCTIONS **********************
  512.  
  513. function SwapImage_identifyBehaviorArguments(fnCallStr) {
  514.   var argList, argArray, numArgGroups, i;
  515.  
  516.   argList = "";
  517.   argArray = extractArgs(fnCallStr);
  518.   numArgGroups = Math.floor((argArray.length - 1) / 3); //args come in triplets
  519.   for (i=0; i<numArgGroups; i++) {          //with each NSobj,IEobj,URL triplet
  520.     if (argList) argList += ",";
  521.     //if no dot in the name, return simple name; else, return NS/IE refs
  522.     argList += (argArray[3*i+1].indexOf(".")==-1)? "objName,other,DEP":"NS4.0ref,IE4.0ref,DEP";
  523.   }
  524.   return argList;
  525. }
  526.  
  527.  
  528. function NavBarGroup_identifyBehaviorArguments(fnCallStr) {
  529.   var argList = '';
  530.   var args = extractArgs(fnCallStr);
  531.   if (args[1] == 'init' || args[1] == 'down') {
  532.     argList = "other,other";
  533.     for (i=3; i+1 < args.length; i+=2)
  534.       argList += ",objName,DEP";
  535.   } else if (args[1] == 'over') {
  536.     argList = "other";
  537.     for (i=2; i+2 < args.length; i+=3)
  538.       argList += ",objName,DEP,DEP";
  539.   } else if (args[1] == 'out') {
  540.     argList = "other";
  541.   }
  542.   return argList;
  543. }
  544.  
  545. //******************* GENERAL FUNCTIONS **********************
  546.  
  547. function displayArray(array, limit, separator, hideElipsis) {
  548.   var retList = array, retVal = '';
  549.   if (array.length > limit) {
  550.     retList = array.slice(0, limit);
  551.     if (!hideElipsis) retList.push('...');
  552.   }
  553.   return retList.join(separator);
  554. }
  555.  
  556. function extractArgs(behFnCallStr){
  557.   var i, theStr, lastPos, argArray;
  558.  
  559.   argArray = getTokens(behFnCallStr,"(),");
  560.   for (i=0; i<argArray.length; i++) {
  561.     theStr = unescQuotes(argArray[i]);
  562.     lastPos = theStr.length-1;
  563.     if (theStr.charAt(0) == "'" && lastPos > 0 && theStr.charAt(lastPos) == "'")
  564.       argArray[i] = theStr.substring(1,lastPos);
  565.   }
  566.   return argArray
  567. }
  568.  
  569. function unescQuotes(theStr){
  570.   var strLen, i, theChar, unescStr = "";
  571.   strLen = theStr.length;
  572.   for(i=0; i<strLen; i++) {
  573.     theChar = theStr.charAt(i);
  574.     if (theChar == "\\" && i < strLen - 1) //if escape char and not end
  575.       theChar = theStr.charAt(++i); //append next char and skip over
  576.     unescStr += theChar;
  577.   }
  578.   return unescStr;
  579. }
  580.  
  581. //Removes any quotes around the given string
  582. function stripQuotes(theStr) {
  583.   var theQuote;
  584.   if (theStr.length > 1) { //if possibly quoted
  585.     theQuote = theStr.charAt(0);
  586.     if ((theQuote == "'" || theQuote == '"') &&
  587.         theStr.charAt(theStr.length-1) == theQuote)
  588.       theStr = theStr.substring(1,theStr.length-1);
  589.   }
  590.   return theStr
  591. }
  592.  
  593. //Removes any spaces at the beginning or end of the string
  594. function stripSpaces(theStr) {
  595.   if (!theStr) theStr = "";  //ensure its not null
  596.   theStr = theStr.replace(/^\s*/,""); //strip leading
  597.   theStr = theStr.replace(/\s*$/,""); //strip trailing
  598.   return theStr;
  599. }
  600.  
  601. function printf() {
  602. var i,numArgs,retStr="",argNum=0,startPos;
  603.  
  604.   numArgs = arguments.length;
  605.   if (numArgs) {
  606.     theStr = arguments[argNum++];
  607.     startPos = 0;  endPos = theStr.indexOf("%s",startPos);
  608.     if (endPos == -1) endPos = theStr.length;
  609.     while (startPos < theStr.length) {
  610.       retStr += theStr.substring(startPos,endPos);
  611.       if (argNum < numArgs && endPos < theStr.length) retStr += arguments[argNum++];
  612.       startPos = endPos+2;  endPos = theStr.indexOf("%s",startPos);
  613.       if (endPos == -1) endPos = theStr.length;
  614.     }
  615.     if (!retStr) retStr = arguments[0];
  616.   }
  617.   return retStr;
  618. }
  619.  
  620.